#ifndef _INPUT_H_
#define _INPUT_H_

#include <unordered_map>
#include <SECore/Events/MouseEvent.h>
#include <functional>
#include <SECore/Signal.h>

namespace SEngine
{
    class Input
    {
    public:
        virtual ~Input() = default;
        static Input & GetInstance();
        
        bool IsKeyPressed(uint8_t key) { return m_key.find(key) != m_key.end() && m_key.at(key); }
        void SetKeyPressed(uint8_t key, bool value) { m_key[key] = value; }

        bool IsMousePressed(MouseButton btn) { return m_mouseKey.find(btn) != m_mouseKey.end() && m_mouseKey.at(btn); }
        void SetMousePressed(MouseButton key, bool value) { m_mouseKey[key] = value; }

        void SetMousePosFn(std::function<std::pair<float, float>()> && fn) { m_getMousePosFn = std::move(fn); }
        std::pair<float, float> GetMousePos() { float x{0.0f}, y{0.0f}; SignalGetMousePos.Invoke(x, y); return std::pair<float, float>{x, y}; }
        std::pair<float, float> GetMouseRelativeState() { float dx{0.0f}, dy{0.0f}; SignalGetMouseRelativeMouseState.Invoke(dx, dy); return std::pair<float, float>{dx, dy}; }

        void SetMouseWheelXY(float x, float y) { m_mouseWheelXY.first = x; m_mouseWheelXY.second = y; }
        std::pair<float, float> GetMouseWheelXY() { auto out = m_mouseWheelXY; m_mouseWheelXY = std::pair<float,float>{0.0f, 0.0f}; return out; }

    public:
        Signal<bool> SignalSetRelativeMouseMode;
        Signal<bool> SignalShowCursor;
        Signal<float&, float&> SignalGetMousePos;
        Signal<float&, float&> SignalGetMouseRelativeMouseState;
        Signal<float, float> SignalWarpMouseInWindow;
 
    private:
        Input() = default;
    
    private:
        std::unordered_map<MouseButton, bool> m_mouseKey;
        std::unordered_map<uint8_t, bool> m_key;
        std::function<std::pair<float, float>()> m_getMousePosFn;
        std::pair<float, float> m_mouseWheelXY;
    };
} // namespace SEngine


#endif